use std::sync::mpsc::{Sender, Receiver};
use specs::{System, Entities, ReadStorage, Component};
use specs::world::Index;
use crate::validators::validator::Validator;

#[derive(Clone)]
pub struct GetMessage<T: Component>
{
    target: Vec<Index>,
    to: Sender<Vec<T>>,
    who: Index,
}

impl<T: Component> GetMessage<T>
{
    pub fn new(target: Vec<Index>, to: Sender<Vec<T>>, who: Index) -> Self {
        GetMessage {
            target,
            to,
            who,
        }
    }
}

pub struct GetSystem<T: Component, V>
{
    rc: Receiver<GetMessage<T>>,
    validator: V,
}

impl<T: Component, V> GetSystem<T, V>
{
    pub fn new(rc: Receiver<GetMessage<T>>, validator: V) -> Self {
        GetSystem {
            rc,
            validator,
        }
    }
}

impl<'a, T: Component + Clone, V: Validator<'a>> System<'a> for GetSystem<T, V>
{
    type SystemData = (
        Entities<'a>,
        ReadStorage<'a, T>,
        V::SystemData,
    );

    fn run(&mut self, data: Self::SystemData) {
        let (entities, value_storage, validation_data) = data;

        if let Ok(report) = self.rc.try_recv() {
            let mut result = Vec::<T>::new();
            let who_entity = entities.entity(report.who);

            for entity_id in report.target {
                let entity = entities.entity(entity_id);

                if self.validator.validate(&validation_data, who_entity, entity) {
                    if let Some(value) = value_storage.get(entity) {
                        result.push(value.clone());
                    }
                } else {
                    println!("validation failed");
                }
            }
            
            report.to.send(result.clone()).unwrap();
        }
    }
}
